package com.example.flow

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import org.junit.Test


/**
 * Flow取消测试
 * 流采用与协程同样的协作取消。像往常一样，流的手机可以是当流在一个可取消的挂起函数
 * （例如delay）中挂起的时候取消
 *
 *
 * @author zhouronghua
 * @time 2022/1/6 10:21 下午
 */
class FlowCancelTest {

    /**
     * 构建一个流
     *
     * @author zhouronghua
     * @time 2022/1/6 10:26 下午
     */
    fun sampleFlow() = flow<Int> {
        // 发射流
        for (i in 1..5) {
            delay(1000)
            println("Emitting $i")
            emit(i)
        }
    }

    /**
     * 测试超时取消
     * 说明：协程超时取消，流也取消
     *
     * @author zhouronghua
     * @time 2022/1/6 10:31 下午
     */
    @Test
    fun test_flow_timeout() = runBlocking<Unit> {
        // 第一个元素能够收集到，第二个元素会超时
        withTimeoutOrNull(1500) {
            sampleFlow().collect { value ->
                println("Collect $value")
            }
        }
        println("流收集结束")
    }

    /**
     * 流取消检测
     *
     * @author zhouronghua
     * @time 2022/1/6 10:34 下午
     */
    @Test
    fun test_flow_cancel_check() = runBlocking {
        try {
            sampleFlow().collect { value ->
                println("Collect $value")
                // 检测接收的流元素需要小于5，否则检测失败，抛出java.lang.IllegalStateException
                check(value < 5)
            }
        } catch (e: Throwable) {
            // 捕捉收集端异常
            println("Exception Caught: $e")
        } finally {
            println("流收集结束")
        }
//        println("收集端通过设置cancelable增加取消条件设置")
//        println("检测到元素大于3取消流因为流没有挂起实际取消不了")
//        try {
//            (1..5).asFlow().collect {
//                println("Collect $it")
//                // 检测接收的流元素需要小于5，否则检测失败，抛出java.lang.IllegalStateException
//                if (it > 3) cancel()
//            }
//        } catch (e: Throwable) {
//            println("Exception2 Caught: $e")
//        } finally {
//            println("流收集结束")
//        }
    }

    /**
     * 构建一个流
     *
     * @author zhouronghua
     * @time 2022/1/6 10:26 下午
     */
    fun sampleNoDelayFlow() = flow<Int> {
        // 发射流
        for (i in 1..5) {
            println("Emitting $i")
            emit(i)
        }
    }

    /**
     * 通过取消协程任务取消流
     *
     * @author zhouronghua
     * @time 2022/1/6 10:56 下午
     */
    @Test
    fun test_flow_cancel_coroutine() = runBlocking {
        println("收集端通过设置cancel增加取消条件设置")
        try {
            sampleNoDelayFlow().collect { value ->

                println("Collect $value")
                // 检测接收的流元素需要大于3，取消协程，抛出JobCancellationException
                if (value > 3) cancel()
            }
        } catch (e: Throwable) {
            // 捕捉收集端异常
            println("Exception Caught: $e")
        } finally {
            println("流收集结束")
        }
    }
}